/**
 * @file snakegamestate.h
 * @brief Snake游戏状态管理类头文件
 *
 * SnakeGameState是Snake游戏的核心状态管理器，负责：
 * - 游戏状态的存储和管理
 * - 游戏数据的序列化和反序列化
 * - 玩家、蛇、食物等游戏对象的管理
 * - 游戏状态变化的通知和事件处理
 * - 与服务器状态的同步
 */

#ifndef SNAKEGAMESTATE_H
#define SNAKEGAMESTATE_H

#include <QObject>              // Qt对象基类
#include <QJsonObject>          // JSON对象处理
#include <QJsonArray>           // JSON数组处理
#include <QVector>              // 向量容器
#include <QHash>                // 哈希表
#include <QPair>                // 键值对
#include <QColor>               // 颜色处理
#include <QTimer>               // 定时器
#include <QDateTime>            // 时间处理

/**
 * @struct Position
 * @brief 位置坐标结构
 */
struct Position {
    int x = 0;                  ///< X坐标
    int y = 0;                  ///< Y坐标
    
    Position() = default;
    Position(int x, int y) : x(x), y(y) {}
    
    bool operator==(const Position& other) const {
        return x == other.x && y == other.y;
    }

    bool operator!=(const Position& other) const {
        return !(*this == other);
    }

    // === 哈希函数支持 ===
    friend uint qHash(const Position& pos, uint seed = 0) {
        return qHash(QPair<int, int>(pos.x, pos.y), seed);
    }
    
    Position operator+(const Position& other) const {
        return Position(x + other.x, y + other.y);
    }
    
    Position operator-(const Position& other) const {
        return Position(x - other.x, y - other.y);
    }
};

/**
 * @enum Direction
 * @brief 移动方向枚举
 */
enum class Direction {
    Up = 0,                     ///< 向上
    Right = 1,                  ///< 向右
    Down = 2,                   ///< 向下
    Left = 3                    ///< 向左
};

/**
 * @struct SnakeData
 * @brief 蛇数据结构
 */
struct SnakeData {
    QString playerId;           ///< 玩家ID
    QString playerName;         ///< 玩家名称
    QVector<Position> body;     ///< 蛇身体位置列表（第一个是头部）
    Direction direction = Direction::Right; ///< 当前移动方向
    Direction nextDirection = Direction::Right; ///< 下一步移动方向
    int score = 0;              ///< 分数
    bool isAlive = true;        ///< 是否存活
    QColor color = Qt::green;   ///< 蛇的颜色
    qint64 lastMoveTime = 0;    ///< 最后移动时间
    int length = 1;             ///< 蛇的长度
    
    /**
     * @brief 获取蛇头位置
     * @return 蛇头位置
     */
    Position getHead() const {
        return body.isEmpty() ? Position() : body.first();
    }
    
    /**
     * @brief 获取蛇尾位置
     * @return 蛇尾位置
     */
    Position getTail() const {
        return body.isEmpty() ? Position() : body.last();
    }
};

/**
 * @struct FoodData
 * @brief 食物数据结构
 */
struct FoodData {
    Position position;          ///< 食物位置
    QString type = "normal";    ///< 食物类型（normal、special、bonus等）
    int value = 1;              ///< 食物价值（分数）
    QColor color = Qt::red;     ///< 食物颜色
    qint64 spawnTime = 0;       ///< 生成时间
    qint64 expireTime = 0;      ///< 过期时间（0表示不过期）
    bool isSpecial = false;     ///< 是否为特殊食物
    
    /**
     * @brief 检查食物是否过期
     * @return true表示已过期
     */
    bool isExpired() const {
        return expireTime > 0 && QDateTime::currentMSecsSinceEpoch() > expireTime;
    }
};

/**
 * @class SnakeGameState
 * @brief Snake游戏状态管理类
 *
 * 管理Snake游戏的完整状态，包括游戏板、玩家、蛇、食物等所有游戏对象。
 * 提供状态更新、序列化、事件通知等功能。
 */
class SnakeGameState : public QObject
{
    Q_OBJECT  // 启用Qt元对象系统

public:
    /**
     * @enum GameStatus
     * @brief 游戏状态枚举
     */
    enum class GameStatus {
        Waiting,                    ///< 等待开始
        Starting,                   ///< 正在开始
        Playing,                    ///< 游戏中
        Paused,                     ///< 暂停
        Finished,                   ///< 已结束
        Error                       ///< 错误状态
    };

    explicit SnakeGameState(QObject *parent = nullptr);
    ~SnakeGameState();

    // === 状态管理 ===
    /**
     * @brief 从JSON更新游戏状态
     * @param stateJson 服务器发送的游戏状态JSON
     */
    void updateFromJson(const QJsonObject &stateJson);

    /**
     * @brief 重置游戏状态
     */
    void reset();

    /**
     * @brief 清空所有数据
     */
    void clear();

    // === 游戏信息获取 ===
    /**
     * @brief 获取游戏状态
     * @return 当前游戏状态
     */
    SnakeGameState::GameStatus getGameStatus() const { return m_gameStatus; }

    /**
     * @brief 获取房间ID
     * @return 当前房间ID
     */
    QString getRoomId() const { return m_roomId; }

    /**
     * @brief 获取游戏板宽度
     * @return 游戏板宽度
     */
    int getBoardWidth() const { return m_boardWidth; }

    /**
     * @brief 获取游戏板高度
     * @return 游戏板高度
     */
    int getBoardHeight() const { return m_boardHeight; }

    /**
     * @brief 获取游戏计数器
     * @return 当前游戏计数
     */
    int getTickCount() const { return m_tickCount; }

    /**
     * @brief 获取游戏速度
     * @return 游戏速度（毫秒）
     */
    int getGameSpeed() const { return m_gameSpeed; }

    // === 蛇数据获取 ===
    /**
     * @brief 获取所有蛇数据
     * @return 蛇数据列表
     */
    const QVector<SnakeData>& getSnakes() const { return m_snakes; }

    /**
     * @brief 获取指定玩家的蛇数据
     * @param playerId 玩家ID
     * @return 蛇数据指针，如果不存在返回nullptr
     */
    const SnakeData* getPlayerSnake(const QString& playerId) const;

    /**
     * @brief 获取当前玩家的蛇数据
     * @return 当前玩家蛇数据指针，如果不存在返回nullptr
     */
    const SnakeData* getCurrentPlayerSnake() const;

    /**
     * @brief 获取存活的蛇数量
     * @return 存活蛇数量
     */
    int getAliveSnakeCount() const;

    // === 食物数据获取 ===
    /**
     * @brief 获取所有食物数据
     * @return 食物数据列表
     */
    const QVector<FoodData>& getFoods() const { return m_foods; }

    /**
     * @brief 获取指定位置的食物
     * @param position 位置
     * @return 食物数据指针，如果不存在返回nullptr
     */
    const FoodData* getFoodAt(const Position& position) const;

    /**
     * @brief 获取食物数量
     * @return 食物数量
     */
    int getFoodCount() const { return m_foods.size(); }

    // === 玩家信息 ===
    /**
     * @brief 设置当前玩家ID
     * @param playerId 玩家ID
     */
    void setCurrentPlayerId(const QString& playerId) { m_currentPlayerId = playerId; }

    /**
     * @brief 获取当前玩家ID
     * @return 当前玩家ID
     */
    QString getCurrentPlayerId() const { return m_currentPlayerId; }

    /**
     * @brief 获取玩家列表
     * @return 玩家ID列表
     */
    QStringList getPlayerIds() const;

    /**
     * @brief 获取玩家数量
     * @return 玩家数量
     */
    int getPlayerCount() const { return m_snakes.size(); }

    // === 游戏逻辑辅助 ===
    /**
     * @brief 检查位置是否在游戏板内
     * @param position 位置
     * @return true表示在游戏板内
     */
    bool isPositionValid(const Position& position) const;

    /**
     * @brief 检查位置是否被蛇占用
     * @param position 位置
     * @param excludePlayerId 排除的玩家ID（可选）
     * @return true表示被占用
     */
    bool isPositionOccupiedBySnake(const Position& position, const QString& excludePlayerId = QString()) const;

    /**
     * @brief 检查位置是否有食物
     * @param position 位置
     * @return true表示有食物
     */
    bool isPositionHasFood(const Position& position) const;

    /**
     * @brief 获取方向向量
     * @param direction 方向
     * @return 方向向量
     */
    static Position getDirectionVector(Direction direction);

    /**
     * @brief 检查方向是否相反
     * @param dir1 方向1
     * @param dir2 方向2
     * @return true表示相反
     */
    static bool areDirectionsOpposite(Direction dir1, Direction dir2);

    /**
     * @brief 将食物类型数字转换为字符串
     * @param typeValue JSON值（可能是数字或字符串）
     * @return 食物类型字符串
     */
    static QString parseFoodType(const QJsonValue& typeValue);

signals:
    // === 状态变化信号 ===
    /**
     * @brief 游戏状态更新信号
     */
    void stateUpdated();

    /**
     * @brief 游戏状态改变信号
     * @param status 新的游戏状态
     */
    void gameStatusChanged(SnakeGameState::GameStatus status);

    /**
     * @brief 游戏板大小改变信号
     * @param width 新宽度
     * @param height 新高度
     */
    void boardSizeChanged(int width, int height);

    // === 蛇相关信号 ===
    /**
     * @brief 蛇添加信号
     * @param playerId 玩家ID
     */
    void snakeAdded(const QString& playerId);

    /**
     * @brief 蛇移除信号
     * @param playerId 玩家ID
     */
    void snakeRemoved(const QString& playerId);

    /**
     * @brief 蛇死亡信号
     * @param playerId 玩家ID
     */
    void snakeDied(const QString& playerId);

    /**
     * @brief 蛇分数改变信号
     * @param playerId 玩家ID
     * @param newScore 新分数
     */
    void snakeScoreChanged(const QString& playerId, int newScore);

    // === 食物相关信号 ===
    /**
     * @brief 食物生成信号
     * @param position 食物位置
     * @param type 食物类型
     */
    void foodSpawned(const Position& position, const QString& type);

    /**
     * @brief 食物消费信号
     * @param position 食物位置
     * @param playerId 消费者玩家ID
     */
    void foodConsumed(const Position& position, const QString& playerId);

    /**
     * @brief 食物过期信号
     * @param position 食物位置
     */
    void foodExpired(const Position& position);

private:
    // === 核心状态数据 ===
    SnakeGameState::GameStatus m_gameStatus;            ///< 游戏状态
    QString m_roomId;                   ///< 房间ID
    QString m_currentPlayerId;          ///< 当前玩家ID
    
    // === 游戏板信息 ===
    int m_boardWidth;                   ///< 游戏板宽度
    int m_boardHeight;                  ///< 游戏板高度
    int m_tickCount;                    ///< 游戏计数器
    int m_gameSpeed;                    ///< 游戏速度（毫秒）
    
    // === 游戏对象 ===
    QVector<SnakeData> m_snakes;        ///< 蛇数据列表
    QVector<FoodData> m_foods;          ///< 食物数据列表
    QHash<QString, int> m_playerSnakeMap; ///< 玩家ID到蛇索引的映射
    
    // === 私有方法 ===
    void parseSnakes(const QJsonArray& snakesArray);
    void parseFoods(const QJsonArray& foodsArray);
    void updatePlayerSnakeMap();
    static QColor generatePlayerColor(const QString& playerId);
    void setGameStatus(SnakeGameState::GameStatus status);
    
    // === 数据转换方法 ===
    static SnakeData parseSnakeData(const QJsonObject& snakeObj);
    static FoodData parseFoodData(const QJsonObject& foodObj);
    static Direction parseDirection(int directionInt);
    static Position parsePosition(const QJsonObject& posObj);
    static QColor generateStaticPlayerColor(const QString& playerId);
};

#endif // SNAKEGAMESTATE_H
